Skip to content

[RDMW-24943][AI-219] Added device management to the Devolutions Agent - #2194

Open
Maxime Forest (forestmaxime) wants to merge 8 commits into
masterfrom
ai/RDMW-24943-AI-219-rdm-device-management-pedm
Open

Maxime Forest (forestmaxime) wants to merge 8 commits into
masterfrom
ai/RDMW-24943-AI-219-rdm-device-management-pedm

Conversation

@forestmaxime

@forestmaxime Maxime Forest (forestmaxime) commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Jira Ticket

Related PRs

  • RDM and DVLS: Devolutions/RDM#22393

Description

Device Management (PEDM) prototype: RDM and DVLS manage the packages of many machines. The Devolutions Agent is the device side. It enrolls with DVLS, reports the package inventory from UniGetUI, and runs the install, update and uninstall operations that an administrator pushes from RDM. Install and uninstall scripts make the lab setup fast.

Technical Information

Changes:

  • New device_management module in the agent: package inventory and operations through the UniGetUI IPC API, with a wait until the installed list shows the expected state.
  • The device management stream to DVLS authenticates with the Agent Identity.
  • Software catalog snapshot synchronization.
  • Fixed the rustls crypto provider initialization.
  • package/install: install-agent.ps1 / .sh (install and enroll, with a retry until the service is ready), uninstall-agent.ps1 / .sh, reinstall-unigetui.ps1, and Start-DevInstallServer.ps1 (a development mode that serves local builds).

Commits

  • 14d83ff - Added device management package inventory and operations to the agent
  • 94ff8a3 - Authenticated the device management stream with the Agent Identity
  • 73ea812 - Added software catalog snapshot synchronization
  • 750c1c8 - Fixed the rustls crypto provider initialization in the agent
  • 6518e61 - Added the Devolutions Agent install and enrollment scripts
  • 9505daa - Added a development mode to the agent install scripts
  • fa979e0 - Retried the agent enrollment until the service is ready
  • b4142c9 - Added the agent uninstall and UniGetUI reinstall scripts

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The device management stream now opens on the Agent Identity channel URL over HTTPS. The agent signs the opening with its identity key and answers the server challenge with a proof. Removed the unauthenticated Enroll call, the device id file, the gRPC URL setting and the installer dialog.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The scripts install the latest agent for Windows (MSI) or Linux x64 (deb), check its SHA-256 hash, turn on Device Management and enroll the device with the token from DEVOLUTIONS_ENROLLMENT_TOKEN.
DEVOLUTIONS_AGENT_DEV_URL installs a locally built agent instead of the published package, and adds the test root CA and broker settings. Start-DevInstallServer.ps1 serves the builds and scripts with that URL set. The default path still installs the latest version from productinfo.json.
Copilot AI balanced review requested due to automatic review settings November 13, 2026 13:28
@github-actions

Copy link
Copy Markdown

Let maintainers know that an action is required on their side

  • Add the label release-required Please cut a new release (Devolutions Gateway, Devolutions Agent, Jetsocat, PowerShell module) when you request a maintainer to cut a new release (Devolutions Gateway, Devolutions Agent, Jetsocat, PowerShell module)

  • Add the label release-blocker Follow-up is required before cutting a new release if a follow-up is required before cutting a new release

  • Add the label publish-required Please publish libraries (`Devolutions.Gateway.Utils`, OpenAPI clients, etc) when you request a maintainer to publish libraries (Devolutions.Gateway.Utils, OpenAPI clients, etc.)

  • Add the label publish-blocker Follow-up is required before publishing libraries if a follow-up is required before publishing libraries

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved critical flaws can execute administrative requests twice, expose UniGetUI credentials, and leave broken installations when MSI uninstallation fails.

10 open issues
What changed in this PR

Adds a device-management prototype to Devolutions Agent, enabling RDM and Devolutions Server to manage device packages through UniGetUI.

Changes:

  • Adds an Agent Identity-authenticated stream for package inventory, remote operations, and software catalog synchronization.
  • Integrates configuration and service startup, supports pinned-version Winget installs, and updates TLS initialization and file permissions.
  • Adds installation, enrollment, removal, and local-development scripts.
File Description
package/​install/​uninstall-agent.sh Removes Linux packages, service, and agent data.
package/​install/​uninstall-agent.ps1 Removes Windows installations, service, and protected data.
package/​install/​Start-DevInstallServer.ps1 Serves local builds and customized setup scripts.
package/​install/​reinstall-unigetui.ps1 Reinstalls UniGetUI from the development server.
package/​install/​install-agent.sh Installs, configures, and enrolls Linux agents.
package/​install/​install-agent.ps1 Installs and enrolls Windows agents with readiness retries.
package/​AgentWindowsManaged/​Actions/​CustomActions.cs Maps device management to the PEDM installer feature.
devolutions-agent/​src/​updater/​security.rs Protects applied file permissions from inheritance.
devolutions-agent/​src/​updater/​mod.rs Exposes the permission helper within the crate.
devolutions-agent/​src/​service.rs Starts the enabled device-management task.
devolutions-agent/​src/​main.rs Initializes the rustls cryptographic provider.
devolutions-agent/​src/​lib.rs Exports the device-management module.
devolutions-agent/​src/​device_management/​unigetui.rs Implements UniGetUI discovery, inventory, and package operations.
devolutions-agent/​src/​device_management/​software_catalog.rs Applies catalog snapshots and records revisions.
devolutions-agent/​src/​device_management/​mod.rs Manages authentication, requests, and inventory reporting.
devolutions-agent/​src/​config.rs Adds optional device-management configuration.
devolutions-agent/​proto/​device_management.proto Defines the bidirectional device-management protocol.
devolutions-agent/​Cargo.toml Adds request-signing and middleware dependencies.
devolutions-agent/​build.rs Generates device-management protocol bindings.
crates/​now-package-broker/​src/​command_builder/​winget.rs Forces version-pinned installs to support downgrades.
Cargo.lock Records the agent’s added dependencies.

Review effort: Balanced

error = format!("{error:#}"),
"UniGetUI endpoint failed"
);
last_error = Some(error);
match &endpoint.transport {
Transport::Tcp(port) => {
let url = format!("http://localhost:{port}{path_and_query}");
let client = reqwest::Client::builder().timeout(timeout).build()?;
Comment on lines +323 to +325
let response = request.send().await.context("UniGetUI TCP request failed")?;
let status = response.status();
let body = response.text().await.context("failed to read UniGetUI response")?;
Write-Host "Removing $($product.DisplayName) $($product.DisplayVersion)..."
$exitCode = (Start-Process msiexec.exe -ArgumentList "/x $($product.PSChildName) /qn /norestart" -Wait -PassThru).ExitCode
if ($exitCode -notin 0, 1605, 3010) {
Write-Host "msiexec failed with exit code $exitCode." -ForegroundColor Yellow
.http2_keep_alive_interval(KEEP_ALIVE_INTERVAL)
.keep_alive_timeout(KEEP_ALIVE_TIMEOUT)
.keep_alive_while_idle(true)
.connect()

match message.payload {
Some(ServerPayload::SyncInventory(_)) => {
if let Some(report) = collect_inventory().await {
};

// UniGetUI returns an empty list for a manager that is not ready, for example just after logon or wake.
if !managers.iter().any(|manager| manager.enabled && manager.installed) {
Comment on lines +436 to +442
let sources = unigetui::sources().await.unwrap_or_else(|error| {
warn!(
error = format!("{error:#}"),
"Failed to collect UniGetUI package sources"
);
Vec::new()
});
catalog_sync::Content::Delete(false) => bail!("invalid software catalog delete request"),
}

atomic_write(&revision_path, request.revision.to_string().as_bytes())?;
Comment on lines +1151 to +1152
bool pedmEnabled = enabledFeatures.Contains(Features.PEDM_FEATURE.Id.Substring(Features.FEATURE_ID_PREFIX.Length));
return ToggleAgentFeature(session, "DeviceManagement", pedmEnabled);

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants